 /**
 * Ext JS Library 3.4.0
 * Copyright(c) 2006-2011 Sencha Inc.
 * licensing@sencha.com
 * http://www.sencha.com/license
 */
Ext.ns('Ext.ux.tree');

/**
 * @class Ext.ux.tree.TreeGridSorter
 * @extends Ext.tree.TreeSorter
 * Provides sorting of nodes in a {@link Ext.ux.tree.TreeGrid}.  The TreeGridSorter automatically monitors events on the
 * associated TreeGrid that might affect the tree's sort order (beforechildrenrendered, append, insert and textchange).
 * Example usage:<br />
 * <pre><code>
 new Ext.ux.tree.TreeGridSorter(myTreeGrid, {
     folderSort: true,
     dir: "desc",
     sortType: function(node) {
         // sort by a custom, typed attribute:
         return parseInt(node.id, 10);
     }
 });
 </code></pre>
 * @constructor
 * @param {TreeGrid} tree
 * @param {Object} config
 */
Ext.ux.tree.TreeGridSorter = Ext.extend(Ext.tree.TreeSorter, {
    /**
     * @cfg {Array} sortClasses The CSS classes applied to a header when it is sorted. (defaults to <tt>['sort-asc', 'sort-desc']</tt>)
     */
    sortClasses : ['sort-asc', 'sort-desc'],
    /**
     * @cfg {String} sortAscText The text displayed in the 'Sort Ascending' menu item (defaults to <tt>'Sort Ascending'</tt>)
     */
    sortAscText : 'Sort Ascending',
    /**
     * @cfg {String} sortDescText The text displayed in the 'Sort Descending' menu item (defaults to <tt>'Sort Descending'</tt>)
     */
    sortDescText : 'Sort Descending',

    constructor : function(tree, config) {
        if(!Ext.isObject(config)) {
            config = {
                property: tree.columns[0].dataIndex || 'text',
                folderSort: true
            }
        }

        Ext.ux.tree.TreeGridSorter.superclass.constructor.apply(this, arguments);

        this.tree = tree;
        tree.on('headerclick', this.onHeaderClick, this);
        tree.ddAppendOnly = true;

        var me = this;
        this.defaultSortFn = function(n1, n2){

            var desc = me.dir && me.dir.toLowerCase() == 'desc',
                prop = me.property || 'text',
                sortType = me.sortType,
                caseSensitive = me.caseSensitive === true,
                leafAttr = me.leafAttr || 'leaf',
                attr1 = n1.attributes,
                attr2 = n2.attributes;

            if(me.folderSort){
                if(attr1[leafAttr] && !attr2[leafAttr]){
                    return 1;
                }
                if(!attr1[leafAttr] && attr2[leafAttr]){
                    return -1;
                }
            }
            var prop1 = attr1[prop],
                prop2 = attr2[prop],
                v1 = sortType ? sortType(prop1) : (caseSensitive ? prop1 : prop1.toUpperCase());
                v2 = sortType ? sortType(prop2) : (caseSensitive ? prop2 : prop2.toUpperCase());
                
            if(v1 < v2){
                return desc ? +1 : -1;
            }else if(v1 > v2){
                return desc ? -1 : +1;
            }else{
                return 0;
            }
        };

        tree.on('afterrender', this.onAfterTreeRender, this, {single: true});
        tree.on('headermenuclick', this.onHeaderMenuClick, this);
    },

    onAfterTreeRender : function() {
        if(this.tree.hmenu){
            this.tree.hmenu.insert(0,
                {itemId:'asc', text: this.sortAscText, cls: 'xg-hmenu-sort-asc'},
                {itemId:'desc', text: this.sortDescText, cls: 'xg-hmenu-sort-desc'}
            );
        }
        this.updateSortIcon(0, 'asc');
    },

    onHeaderMenuClick : function(c, id, index) {
        if(id === 'asc' || id === 'desc') {
            this.onHeaderClick(c, null, index);
            return false;
        }
    },

    onHeaderClick : function(c, el, i) {
        if(c && !this.tree.headersDisabled){
            var me = this;

            me.property = c.dataIndex;
            me.dir = c.dir = (c.dir === 'desc' ? 'asc' : 'desc');
            me.sortType = c.sortType;
            me.caseSensitive === Ext.isBoolean(c.caseSensitive) ? c.caseSensitive : this.caseSensitive;
            me.sortFn = c.sortFn || this.defaultSortFn;

            this.tree.root.cascade(function(n) {
                if(!n.isLeaf()) {
                    me.updateSort(me.tree, n);
                }
            });

            this.updateSortIcon(i, c.dir);
        }
    },

    // private
    updateSortIcon : function(col, dir){
        var sc = this.sortClasses,
            hds = this.tree.innerHd.select('td').removeClass(sc);
        hds.item(col).addClass(sc[dir == 'desc' ? 1 : 0]);
    }
});

/*!
 * Ext JS Library 3.4.0
 * Copyright(c) 2006-2011 Sencha Inc.
 * licensing@sencha.com
 * http://www.sencha.com/license
 */
/**
 * @class Ext.tree.ColumnResizer
 * @extends Ext.util.Observable
 */
Ext.tree.ColumnResizer = Ext.extend(Ext.util.Observable, {
    /**
     * @cfg {Number} minWidth The minimum width the column can be dragged to.
     * Defaults to <tt>14</tt>.
     */
    minWidth: 14,

    constructor: function(config){
        Ext.apply(this, config);
        Ext.tree.ColumnResizer.superclass.constructor.call(this);
    },

    init : function(tree){
        this.tree = tree;
        tree.on('render', this.initEvents, this);
    },

    initEvents : function(tree){
        tree.mon(tree.innerHd, 'mousemove', this.handleHdMove, this);
        this.tracker = new Ext.dd.DragTracker({
            onBeforeStart: this.onBeforeStart.createDelegate(this),
            onStart: this.onStart.createDelegate(this),
            onDrag: this.onDrag.createDelegate(this),
            onEnd: this.onEnd.createDelegate(this),
            tolerance: 3,
            autoStart: 300
        });
        this.tracker.initEl(tree.innerHd);
        tree.on('beforedestroy', this.tracker.destroy, this.tracker);
    },

    handleHdMove : function(e, t){
        var hw = 5,
            x = e.getPageX(),
            hd = e.getTarget('.x-treegrid-hd', 3, true);
        
        if(hd){                                 
            var r = hd.getRegion(),
                ss = hd.dom.style,
                pn = hd.dom.parentNode;
            
            if(x - r.left <= hw && hd.dom !== pn.firstChild) {
                var ps = hd.dom.previousSibling;
                while(ps && Ext.fly(ps).hasClass('x-treegrid-hd-hidden')) {
                    ps = ps.previousSibling;
                }
                if(ps) {                    
                    this.activeHd = Ext.get(ps);
                    ss.cursor = Ext.isWebKit ? 'e-resize' : 'col-resize';
                }
            } else if(r.right - x <= hw) {
                var ns = hd.dom;
                while(ns && Ext.fly(ns).hasClass('x-treegrid-hd-hidden')) {
                    ns = ns.previousSibling;
                }
                if(ns) {
                    this.activeHd = Ext.get(ns);
                    ss.cursor = Ext.isWebKit ? 'w-resize' : 'col-resize';                    
                }
            } else{
                delete this.activeHd;
                ss.cursor = '';
            }
        }
    },

    onBeforeStart : function(e){
        this.dragHd = this.activeHd;
        return !!this.dragHd;
    },

    onStart : function(e){
        this.dragHeadersDisabled = this.tree.headersDisabled;
        this.tree.headersDisabled = true;
        this.proxy = this.tree.body.createChild({cls:'x-treegrid-resizer'});
        this.proxy.setHeight(this.tree.body.getHeight());

        var x = this.tracker.getXY()[0];

        this.hdX = this.dragHd.getX();
        this.hdIndex = this.tree.findHeaderIndex(this.dragHd);

        this.proxy.setX(this.hdX);
        this.proxy.setWidth(x-this.hdX);

        this.maxWidth = this.tree.outerCt.getWidth() - this.tree.innerBody.translatePoints(this.hdX).left;
    },

    onDrag : function(e){
        var cursorX = this.tracker.getXY()[0];
        this.proxy.setWidth((cursorX-this.hdX).constrain(this.minWidth, this.maxWidth));
    },

    onEnd : function(e){
        var nw = this.proxy.getWidth(),
            tree = this.tree,
            disabled = this.dragHeadersDisabled;
        
        this.proxy.remove();
        delete this.dragHd;
        
        tree.columns[this.hdIndex].width = nw;
        tree.updateColumnWidths();
        
        setTimeout(function(){
            tree.headersDisabled = disabled;
        }, 100);
    }
});

/*!
 * Ext JS Library 3.4.0
 * Copyright(c) 2006-2011 Sencha Inc.
 * licensing@sencha.com
 * http://www.sencha.com/license
 */
/**
 * @class Ext.ux.tree.TreeGridNodeUI
 * @extends Ext.tree.TreeNodeUI
 */
Ext.ux.tree.TreeGridNodeUI = Ext.extend(Ext.tree.TreeNodeUI, {
    isTreeGridNodeUI: true,

    renderElements : function(n, a, targetNode, bulkRender){
        var t = n.getOwnerTree(),
            cols = t.columns,
            occ = t.onlyChildCheckable,
            c = cols[0],
            i, buf, len;
        this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
        var cb = Ext.isBoolean(a.checked);
        if(t.checkedFn) {
            a.checked = t.checkedFn(n);
        }
        if(!Ext.isDefined(a.children)) {
            a.children =[];
        }
        var buf = [
             '<tbody class="x-tree-node">',
                '<tr ext:tree-node-id="', n.id ,'" class="x-tree-node-el ',a.children.length ? 'x-tree-node-collapsed':'x-tree-node-leaf ', a.cls, '">',
                    '<td class="x-treegrid-col">',
                        '<span class="x-tree-node-indent">', this.indentMarkup, "</span>",
                        '<img src="', this.emptyIcon, a.children.length? '" class="x-tree-ec-icon x-tree-elbow" />':'" style="display:none" class="x-tree-ec-icon x-tree-ec-icon x-tree-elbow-end" />',
                        '<img src="', a.icon || this.emptyIcon, '" style="display:none" class="x-tree-node-icon', (a.icon ? " x-tree-node-inline-icon" : ""), (a.iconCls ? " "+a.iconCls : ""), '" unselectable="on" />',
                        //cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : '/>')) : '',
                        '<a hidefocus="on" class="x-tree-node-anchor" href="', a.href ? a.href : '#', '" tabIndex="1" ',
                            a.hrefTarget ? ' target="'+a.hrefTarget+'"' : '', '>',
                        '<span unselectable="on"',a.children.length==0?'':' style="color:#E68C3A"','>', 
                            (!occ || !a.children || a.children.length==0) ? (t.cm ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : '/>')) : '') : '',
                            '&nbsp&nbsp',c.renderer ? c.renderer(a[c.dataIndex],a,{json:n.attributes,id:n.attributes.id}) : ( a[c.dataIndex] || a.text || ''), '</span></a>',
                    '</td>'
        ];
      
        
        for(i = 1, len = cols.length; i < len; i++){
            c = cols[i];
            buf.push(
                    '<td class="x-treegrid-col ', (c.cls ? c.cls : ''), '">',
                        '<div selectable="on" class="x-treegrid-text '+ (c.header == Ext.langs.handler ? 'x-grid3-td-ys_action':'')+'"', (c.align ? ' style="text-align: ' + c.align + ';"' : ''), '>',
                            c.renderer ? c.renderer(a[c.dataIndex],a,{json:n.attributes,id:n.attributes.id}) : ( a[c.dataIndex] || ''),
                        '</div>',
                    '</td>'
            );
        }

        buf.push(
            '</tr><tr class="x-tree-node-ct"><td colspan="', cols.length, '">',
            '<table class="x-treegrid-node-ct-table" cellpadding="0" cellspacing="0" style="table-layout: fixed; display: none; width: ', t.innerCt.getWidth() ,'px;"><colgroup>'
        );
        for(i = 0, len = cols.length; i<len; i++) {
            buf.push('<col style="width: ', cols[i].width ,'px;" />');
        }
        buf.push('</colgroup></table></td></tr></tbody>');

        if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
            this.wrap = Ext.DomHelper.insertHtml("beforeBegin", n.nextSibling.ui.getEl(), buf.join(''));
        }else{
            this.wrap = Ext.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(''));
        }

        this.elNode = this.wrap.childNodes[0];
        this.ctNode = this.wrap.childNodes[1].firstChild.firstChild;
        var cs = this.elNode.firstChild.childNodes;
        this.indentNode = cs[0];
        this.ecNode = cs[1];
        this.iconNode = cs[2];
        this.anchor = cs[3];
        this.textNode = cs[3].firstChild;
        
        if(t.cm){
            this.checkbox = this.textNode.childNodes[0];
            // fix for IE6
            try {
                this.checkbox.defaultChecked = this.checkbox.checked;
            }catch(e){}
        }
        if(!this.node.childrenRendered) {
            this.node.renderChildren(true);
        }
    },
    // private
    animExpand : function(cb){
        this.ctNode.style.display = "";
        Ext.ux.tree.TreeGridNodeUI.superclass.animExpand.call(this, cb);
    },
    //unselectable
     // private
    onCheckChange : function() {
        var me = this,t = this.node.getOwnerTree();
        var checked = this.checkbox.checked;
        if(t.singleSelect) {
            resetNode();
            setNodeSelfChecked(this.node,checked);
        } else if(t.toggleChild === false && this.node.ui.checkbox) {
            try {
                this.node.ui.checkbox.defaultChecked = checked;
                this.node.ui.checkbox.checked = checked; 
            }catch(e){}
            this.node.attributes.checked = checked;
        } else {
            setChecked(this.node,checked);
            var nd = this.node;
            while(nd.parentNode) {
                nd = nd.parentNode;
                if(nd.attributes.checked == checked) {
                    break;
                }
                for(var i = 0,len =  nd.childNodes.length ; i < len;i++) {
                    var node = nd.childNodes[i];
                    if(node.attributes.checked != checked) {
                        break;
                    }
                }
                if(((i == len && checked) || !checked) && nd.ui.checkbox) {
                    nd.ui.checkbox.defaultChecked = checked;
                    nd.ui.checkbox.checked = checked; 
                    nd.attributes.checked = checked;
                }
            }
        }
        //fire event;
        this.fireEvent('checkchange', this.node, checked);

        function setChecked(node,checked) {
            setNodeSelfChecked(node,checked);
            //node.ui.fireEvent('checkchange', node, checked);
            var childNodes = node.childNodes;
            if(childNodes) {
                Ext.each(childNodes,function(n) {
                    setChecked(n,checked);
                });
            }
        }
        
        function setNodeSelfChecked(node,checked) {
            if(node.ui.checkbox) {
                try {
                    node.ui.checkbox.defaultChecked = checked;
                    node.ui.checkbox.checked = checked; 
                } catch(e) {}
                node.attributes.checked = checked;
            }
        }
        
        function resetNode() {
            setChecked(t.root,false);
        }
        
    }
});

Ext.ux.tree.TreeGridRootNodeUI = Ext.extend(Ext.tree.TreeNodeUI, {
    isTreeGridNodeUI: true,

    // private
    render : function(){
        if(!this.rendered){
            this.wrap = this.ctNode = this.node.ownerTree.innerCt.dom;
            this.node.expanded = true;
        }

        if(Ext.isWebKit) {
            // weird table-layout: fixed issue in webkit
            var ct = this.ctNode;
            ct.style.tableLayout = null;
            (function() {
                ct.style.tableLayout = 'fixed';
            }).defer(1);
        }
    },

    destroy : function(){
        if(this.elNode){
            Ext.dd.Registry.unregister(this.elNode.id);
        }
        delete this.node;
    },

    collapse : Ext.emptyFn,
    expand : Ext.emptyFn
});

/*!
 * Ext JS Library 3.4.0
 * Copyright(c) 2006-2011 Sencha Inc.
 * licensing@sencha.com
 * http://www.sencha.com/license
 */
/**
 * @class Ext.ux.tree.TreeGridLoader
 * @extends Ext.tree.TreeLoader
 */
Ext.ux.tree.TreeGridLoader = Ext.extend(Ext.tree.TreeLoader, {
    preloadChildren:true,
    
    createNode : function(attr) {
        if (!attr.uiProvider) {
            attr.uiProvider = Ext.ux.tree.TreeGridNodeUI;
        }
        return Ext.tree.TreeLoader.prototype.createNode.call(this, attr);
    },
    processResponse : function(response, node, callback, scope){
        var json = response.responseText;
        try {
            var o = (response.responseData || Ext.decode(json))[this.dataRoot];
            this.store = o;
            node.beginUpdate();
            for(var i = 0, len = o.length; i < len; i++){
                var n = this.createNode(o[i]);
                if(n){
                    node.appendChild(n);
                    if(this.preloadChildren) {
                        this.doPreload(n);
                    }
                }
            }
            node.endUpdate();
            this.runCallback(callback, scope || node, [node]);
        }catch(e){
            this.handleFailure(response);
        }
    },
   render : function(bulkRender){
        var n = this.node, a = n.attributes;
        var targetNode = n.parentNode ?
              n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;

        if(!this.rendered){
            this.rendered = true;

            this.renderElements(n, a, targetNode, bulkRender);

            if(a.qtip){
               if(this.textNode.setAttributeNS){
                   this.textNode.setAttributeNS("ext", "qtip", a.qtip);
                   if(a.qtipTitle){
                       this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
                   }
               }else{
                   this.textNode.setAttribute("ext:qtip", a.qtip);
                   if(a.qtipTitle){
                       this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
                   }
               }
            }else if(a.qtipCfg){
                a.qtipCfg.target = Ext.id(this.textNode);
                Ext.QuickTips.register(a.qtipCfg);
            }
            this.initEvents();
            if(!this.node.expanded){
                this.updateExpandIcon(true);
            }
        }else{
            if(bulkRender === true) {
                this.wrap && targetNode.appendChild(this.wrap);
            }
        }
    }
});

/*!
 * Ext JS Library 3.4.0
 * Copyright(c) 2006-2011 Sencha Inc.
 * licensing@sencha.com
 * http://www.sencha.com/license
 */
(function() {
    Ext.override(Ext.list.Column, {
        init : function() {    
            var types = Ext.data.Types || {},
                st = this.sortType;
            if(this.type){
                if(Ext.isString(this.type)){
                    this.type = Ext.data.Types[this.type.toUpperCase()] || types.AUTO;
                }
            }else{
                this.type = types.AUTO;
            }

            // named sortTypes are supported, here we look them up
            if(Ext.isString(st)){
                this.sortType = Ext.data.SortTypes[st];
            }else if(Ext.isEmpty(st)){
                //this.sortType = this.type.sortType;
            }
        }
    });

    Ext.tree.Column = Ext.extend(Ext.list.Column, {});
    Ext.tree.NumberColumn = Ext.extend(Ext.list.NumberColumn, {});
    Ext.tree.DateColumn = Ext.extend(Ext.list.DateColumn, {});
    Ext.tree.BooleanColumn = Ext.extend(Ext.list.BooleanColumn, {});

    Ext.reg('tgcolumn', Ext.tree.Column);
    Ext.reg('tgnumbercolumn', Ext.tree.NumberColumn);
    Ext.reg('tgdatecolumn', Ext.tree.DateColumn);/*!
 * Ext JS Library 3.4.0
 * Copyright(c) 2006-2011 Sencha Inc.
 * licensing@sencha.com
 * http://www.sencha.com/license
 */


/**
 * @class Ext.ux.tree.TreeGrid
 * @extends Ext.tree.TreePanel
 * 
 * @xtype treegrid
 */
Ext.ux.tree.TreeGrid = Ext.extend(Ext.tree.TreePanel, {
    rootVisible : false,
    useArrows : true,
    lines : false,
    borderWidth : Ext.isBorderBox ? 0 : 2, // the combined left/right border for each cell
    cls : 'x-treegrid',
    cm:true,
    columnResize : true,
    enableSort : true,
    reserveScrollOffset : true,
    useArrows:false,
    enableSort:false,
    preloadChildren:true,
    singleSelect: false,
    onlyChildCheckable:false,
    autoSearch: true,
    requestMethod: 'post',
    enableHdMenu:false,
    dataRoot:'addon',
   // plugins:[new Ext.ux.tree.TreeGridRowAction()],
    
    columnsText : 'Columns',

    initComponent : function() {
        if(!this.root) {
            this.root = new Ext.tree.AsyncTreeNode({text: 'Root'});
        }
        
        // initialize the loader
        var l = this.loader;
        if(!l){
            /*l = new Ext.ux.tree.TreeGridLoader({
                dataUrl: this.dataUrl,
                requestMethod: this.requestMethod,
                store: this.store
            }); */
            l = new Ext.ux.tree.TreeGridLoader({
                    dataUrl: this.url || this.dataUrl,
                    dataRoot:this.dataRoot,
                    baseParams: this.params || {}
                });
        }else if(Ext.isObject(l) && !l.load){
            l = new Ext.ux.tree.TreeGridLoader(l);
        }
        this.loader = l;
        
        this.loader.on('beforeload',function(treegrid,node) {
            this.body.mask('Loading...','x-mask-loading');
        },this);
        this.loader.on('load',function(treegrid,node) {
            this.body.unmask();
        },this);

        Ext.ux.tree.TreeGrid.superclass.initComponent.call(this);                    
        
        this.initColumns();
        
        if(this.enableSort) {
            this.treeGridSorter = new Ext.ux.tree.TreeGridSorter(this, this.enableSort);
        }
        
        if(this.columnResize){
            this.colResizer = new Ext.tree.ColumnResizer(this.columnResize);
            this.colResizer.init(this);
        }

        // add by klj; cancel default dblclick
        this.on('beforedblclick',function () {
            if(this.fireDetail) {
                return false
            }
        });
        
        var c = this.columns;
        if(!this.internalTpl){                                
            this.internalTpl = new Ext.XTemplate(
                '<div class="x-grid3-header">',
                    '<div class="x-treegrid-header-inner">',
                        '<div class="x-grid3-header-offset">',
                            '<table style="table-layout: fixed;" cellspacing="0" cellpadding="0" border="0"><colgroup><tpl for="columns"><col /></tpl></colgroup>',
                            '<thead><tr class="x-grid3-hd-row">',
                            '<tpl for="columns">',
                            '<td class="x-grid3-hd x-grid3-cell x-treegrid-hd" style="text-align: {align};" id="', this.id, '-xlhd-{#}">',
                                '<div class="x-grid3-hd-inner x-treegrid-hd-inner" unselectable="on">',
                                     this.enableHdMenu ? '<a class="x-grid3-hd-btn" href="#"></a>' : '',
                                     '{header}<img class="x-grid3-sort-icon" src="', Ext.BLANK_IMAGE_URL, '" />',
                                 '</div>',
                            '</td></tpl>',
                            '</tr></thead><tbody><tr class="head-filter">',
                            '<tpl for="columns">',
                            '<td class="x-treegrid-hd-filter" style="text-align: {align};" id="', this.id, '-xlhd-{#}-filter">',
                                '<div class="x-small-editor" selectable="on" id="',this.id,'-{dataIndex}-filter"></div>',
                            '</td></tpl>',
                            '</tr></tbody>',
                        '</table>',
                    '</div></div>',
                '</div>',
                '<div class="x-treegrid-root-node">',
                    '<table class="x-treegrid-root-table" cellpadding="0" cellspacing="0" style="table-layout: fixed;"></table>',
                '</div>'
            );
        }
        
        if(!this.colgroupTpl) {
            this.colgroupTpl = new Ext.XTemplate(
                '<colgroup><tpl for="columns"><col style="width: {width}px"/></tpl></colgroup>'
            );
        }
    },

    initColumns : function() {
        var cs = this.columns,
            len = cs.length, 
            columns = [],
            i, c;

        for(i = 0; i < len; i++){
            c = cs[i];
            //add column width
            //edit by klj 2013-07-17
            if(c.hidden) {
                c.width = 0;
            } else if(c.width !== 0 && !c.width) {
                c.width = 100;
            }
            if(!c.isColumn) {
                c.xtype = c.xtype ? (/^tg/.test(c.xtype) ? c.xtype : 'tg' + c.xtype) : 'tgcolumn';
                c = Ext.create(c);
            }
            c.init(this);
            columns.push(c);
            
            if(this.enableSort !== false && c.sortable !== false) {
                c.sortable = true;
                this.enableSort = true;
            }
        }

        this.columns = columns;
    },

    onRender : function(){
        Ext.tree.TreePanel.superclass.onRender.apply(this, arguments);

        this.el.addClass('x-treegrid');
        
        this.outerCt = this.body.createChild({
            cls:'x-tree-root-ct x-treegrid-ct ' + (this.useArrows ? 'x-tree-arrows' : this.lines ? 'x-tree-lines' : 'x-tree-no-lines')
        });
        
        this.internalTpl.overwrite(this.outerCt, {columns: this.columns});
        
        this.mainHd = Ext.get(this.outerCt.dom.firstChild);
        this.innerHd = Ext.get(this.mainHd.dom.firstChild);
        this.innerBody = Ext.get(this.outerCt.dom.lastChild);
        this.innerCt = Ext.get(this.innerBody.dom.firstChild);
        
        this.colgroupTpl.insertFirst(this.innerCt, {columns: this.columns});
        
        if(this.hideHeaders){
            this.el.child('.x-grid3-header').setDisplayed('none');
        }
        else if(this.enableHdMenu !== false){
            this.hmenu = new Ext.menu.Menu({id: this.id + '-hctx'});
            if(this.enableColumnHide !== false){
                this.colMenu = new Ext.menu.Menu({id: this.id + '-hcols-menu'});
                this.colMenu.on({
                    scope: this,
                    beforeshow: this.beforeColMenuShow,
                    itemclick: this.handleHdMenuClick
                });
                this.hmenu.add({
                    itemId:'columns',
                    hideOnClick: false,
                    text: this.columnsText,
                    menu: this.colMenu,
                    iconCls: 'x-cols-icon'
                });
            }
            this.hmenu.on('itemclick', this.handleHdMenuClick, this);
        }
        var treegrid = this; 
        this.on('afterrender',function(p) {
            p.createFilterHeader();
        });
    },
    
    //add filter
    //klj
    createFilterHeader:function() {
        var me = this;
        var filterBody = this.innerHd.child('tbody');
        this.filterFields = [];
        this.hasFilter = false;
        Ext.each(this.columns,function(item,i) {
            if(item.filter) {
                me.hasFilter = true;
                var tempId = me.id+'-'+item.dataIndex;
                var filterConfig = {};
                Ext.apply(filterConfig, item.filter,{
                    dataIndex: item.dataIndex,
                    id:'f_'+ tempId,
                    enableKeyEvents:true,
                    listeners : {
                        specialkey: function(field, e){
                            if (e.getKey() == e.ENTER) {
                                me.applyFilter();
                            }
                        }
                    },
                    filterName:item.filter.name||item.dataIndex,
                    stateful:false,
                    xtype:'textfield'
                });
                if(me.autoSearch) {
                    if(filterConfig.xtype == 'textfield') {
                        filterConfig.xtype = 'trigger';
                        filterConfig.listeners = filterConfig.listeners || {};
                        filterConfig.onTriggerClick = function(){
                            me.applyFilter();
                        };
                        filterConfig.triggerClass = 'x-form-search-trigger';
                        filterConfig.hideTrigger = true;
                    }
                }
                    
                filterPanel = new Ext.Container({
                    renderTo: tempId+'-filter',
                    id : 'p_' + tempId,
                    layout: "fit",
                    autoWidth:true,
                    defaults:{style:'text-align:left'},
                    style:'padding:1px;',
                    items: filterConfig,
                    stateful: false
                });
                
                if(me.autoSearch) {
                    if(filterConfig.xtype == 'trigger') {
                        filterPanel.el.on({
                            mouseenter:function(e,t)  {
                                this.setHideTrigger(false);
                            },
                            mouseleave:function(e,t) {
                                this.setHideTrigger(true);
                            },
                            scope:filterPanel.get(0)
                        });
                    } else if(filterConfig.xtype == 'combo' || filterConfig.xtype == 'combofield'){
                        filterPanel.get(0).on('select',function() {
                            me.applyFilter();
                        });
                    } else {
                        filterPanel.get(0).on('confirm',function() {
                            me.applyFilter();
                        });
                        filterPanel.get(0).on('cancel',function() {
                            me.applyFilter();
                        });
                    }
                }
                
                //封装原来的对像，等着destroy
                me.filterFields.push(filterPanel);
            }
        });
        if(!this.hasFilter) {
            filterBody.setStyle('display','none');
        }
    },
    
    applyFilter: function()
    {
        var me = this,
            filterArr = [];
        for (var v=0; v < me.filterFields.length; v++){
            el = me.filterFields[v].get(0);
            //用于验证，只要表单里有不合格的，则所有的查询都不可用
            //希望这里只有一项搜索
            if(!el.isValid())
                return;
            if(el.xtype == 'daterangefield'||el.xtype == 'floatrangefield') {
                var sValue = el.getValue().split(el.delimiter);
                if(sValue.length < 2) {
                    delete me.loader.baseParams[el.filterName+'_start'];
                    delete me.loader.baseParams[el.filterName+'_end'];
                } else {
                    me.loader.baseParams[el.filterName+'_start'] = sValue[0]+(el.xtype == 'daterangefield'&&!el.onlyDate?' 00:00:00':'');
                    me.loader.baseParams[el.filterName+'_end'] = sValue[1]+(el.xtype == 'daterangefield'&&!el.onlyDate?' 23:59:59':'');
                    if(sValue[0]=='') {
                        delete me.loader.baseParams[el.filterName+'_start'];
                    }
                    if(sValue[1]=='') {
                        delete me.loader.baseParams[el.filterName+'_end'];
                    }
                    filterArr.push({xtype:el.xtype,value:el.getValue(),dataIndex:v});
                }
            } else {
                var sValue = el.getValue();
                if(Ext.isString(sValue) && sValue.trim) {
                    sValue = sValue.trim();
                }
                if(Ext.isArray(sValue)) {
                    ZM.clearArrayParam(me.loader.baseParams,el.filterName);
                    Ext.each(sValue,function(v,i) {
                        me.loader.baseParams[el.filterName+'['+i+']'] = v;
                    });
                } else if(Ext.isEmpty(sValue))
                {
                    delete me.loader.baseParams[el.filterName];
                }
                else
                {
                    me.loader.baseParams[el.filterName] = sValue;
                    filterArr.push({xtype:el.xtype,value:sValue,dataIndex:v});
                }
            }
        };
        me.loader.load(me.getRootNode());
    },

    setRootNode : function(node){
        node.attributes.uiProvider = Ext.ux.tree.TreeGridRootNodeUI;        
        node = Ext.ux.tree.TreeGrid.superclass.setRootNode.call(this, node);
        if(this.innerCt) {
            this.colgroupTpl.insertFirst(this.innerCt, {columns: this.columns});
        }
        return node;
    },
    
    clearInnerCt : function(){
        if(Ext.isIE){
            var dom = this.innerCt.dom;
            while(dom.firstChild){
                dom.removeChild(dom.firstChild);
            }
        }else{
            Ext.ux.tree.TreeGrid.superclass.clearInnerCt.call(this);
        }
    },
    
    initEvents : function() {
        Ext.ux.tree.TreeGrid.superclass.initEvents.apply(this, arguments);

        this.mon(this.innerBody, 'scroll', this.syncScroll, this);
        //buffer 为了等row selected
        this.mon(this.innerBody,'mousedown',this.handleBodyDown,this,{buffer:250});
        this.mon(this.innerBody,'dblclick',this.handlerDblClick,this,{buffer:250});
        this.mon(this.innerHd, 'click', this.handleHdDown, this);
        this.mon(this.mainHd, {
            scope: this,
            mouseover: this.handleHdOver,
            mouseout: this.handleHdOut
        });
    },
    
    onResize : function(w, h) {
        Ext.ux.tree.TreeGrid.superclass.onResize.apply(this, arguments);
        
        var bd = this.innerBody.dom;
        var hd = this.innerHd.dom;

        if(!bd){
            return;
        }

        if(Ext.isNumber(h)){
            bd.style.height = this.body.getHeight(true) - hd.offsetHeight + 'px';
        }

        if(Ext.isNumber(w)){                        
            var sw = Ext.num(this.scrollOffset, Ext.getScrollBarWidth());
            if(this.reserveScrollOffset || ((bd.offsetWidth - bd.clientWidth) > 10)){
                this.setScrollOffset(sw);
            }else{
                var me = this;
                setTimeout(function(){
                    me.setScrollOffset(bd.offsetWidth - bd.clientWidth > 10 ? sw : 0);
                }, 10);
            }
        }
    },

    updateColumnWidths : function() {
        var cols = this.columns,
            colCount = cols.length,
            groups = this.outerCt.query('colgroup'),
            groupCount = groups.length,
            c, g, i, j;

        for(i = 0; i<colCount; i++) {
            c = cols[i];
            for(j = 0; j<groupCount; j++) {
                g = groups[j];
                g.childNodes[i].style.width = (c.hidden ? 0 : c.width) + 'px';
            }
        }
        
        for(i = 0, groups = this.innerHd.query('td'), len = groups.length; i<len; i++) {
            c = Ext.fly(groups[i]);
            if(cols[i] && cols[i].hidden) {
                c.addClass('x-treegrid-hd-hidden');
            }
            else {
                c.removeClass('x-treegrid-hd-hidden');
            }
        }

        var tcw = this.getTotalColumnWidth();                        
        Ext.fly(this.innerHd.dom.firstChild).setWidth(tcw + (this.scrollOffset || 0));
        this.outerCt.select('table').setWidth(tcw);
        this.syncHeaderScroll();    
        
        if(this.hasFilter) {
            Ext.each(this.filterFields,function(el){
                el.doLayout();
            });
        }
    },
                    
    getVisibleColumns : function() {
        var columns = [],
            cs = this.columns,
            len = cs.length,
            i;
            
        for(i = 0; i<len; i++) {
            if(!cs[i].hidden) {
                columns.push(cs[i]);
            }
        }        
        return columns;
    },

    getTotalColumnWidth : function() {
        var total = 0;
        for(var i = 0, cs = this.getVisibleColumns(), len = cs.length; i<len; i++) {
            total += cs[i].width;
        }
        return total;
    },

    setScrollOffset : function(scrollOffset) {
        this.scrollOffset = scrollOffset;                        
        this.updateColumnWidths();
    },

    // private
    handleHdDown : function(e, t){
        var hd = e.getTarget('.x-treegrid-hd');

        if(hd && Ext.fly(t).hasClass('x-grid3-hd-btn')){
            var ms = this.hmenu.items,
                cs = this.columns,
                index = this.findHeaderIndex(hd),
                c = cs[index],
                sort = c.sortable;
                
            e.stopEvent();
            Ext.fly(hd).addClass('x-grid3-hd-menu-open');
            this.hdCtxIndex = index;
            
            this.fireEvent('headerbuttonclick', ms, c, hd, index);
            
            this.hmenu.on('hide', function(){
                Ext.fly(hd).removeClass('x-grid3-hd-menu-open');
            }, this, {single:true});
            
            this.hmenu.show(t, 'tl-bl?');
        }
        else if(hd) {
            var index = this.findHeaderIndex(hd);
            this.fireEvent('headerclick', this.columns[index], hd, index);
        }
    },
    /*
     * add body action (columns action);
     * kuanglijun 
     */ 
    handleBodyDown:function(e,t) {
        if(t.tagName == 'A'){
                    var fn = eval('this.'+(t.title||'_tmp'));
                    if(!Ext.isFunction(fn))
                        return;
                    var row = e.getTarget('.x-tree-node-el');
                    var selectednode = this.getSelectionModel().getSelectedNode();
                    var attr = {json:selectednode.attributes};
                    if(attr.json.id == t.id.substr(1)) {
                        var result = '';
                            if(t.href){
                                var regex=/(.*?)#([^\_]+)/;
                                var s = t.href.match(regex);
                                if(s)
                                    result=s[2];
                            }
                            eval('this.'+t.title+'(attr,"'+result+'")');
                    }
                }
                //e.stopEvent();
    },
    handlerDblClick:function (e,t) {
        // body...
        var selectednode = this.getSelectionModel().getSelectedNode();
        if(this.fireDetail) {
            this.fireDetail({json:selectednode.attributes});
        }
    },
    // private
    handleHdOver : function(e, t){                    
        var hd = e.getTarget('.x-treegrid-hd');                        
        if(hd && !this.headersDisabled){
            index = this.findHeaderIndex(hd);
            this.activeHdRef = t;
            this.activeHdIndex = index;
            var el = Ext.get(hd);
            this.activeHdRegion = el.getRegion();
            el.addClass('x-grid3-hd-over');
            this.activeHdBtn = el.child('.x-grid3-hd-btn');
            if(this.activeHdBtn){
                this.activeHdBtn.dom.style.height = (hd.firstChild.offsetHeight-1)+'px';
            }
        }
    },
    
    // private
    handleHdOut : function(e, t){
        var hd = e.getTarget('.x-treegrid-hd');
        if(hd && (!Ext.isIE || !e.within(hd, true))){
            this.activeHdRef = null;
            Ext.fly(hd).removeClass('x-grid3-hd-over');
            hd.style.cursor = '';
        }
    },
                    
    findHeaderIndex : function(hd){
        hd = hd.dom || hd;
        var cs = hd.parentNode.childNodes;
        for(var i = 0, c; c = cs[i]; i++){
            if(c == hd){
                return i;
            }
        }
        return -1;
    },
    
    // private
    beforeColMenuShow : function(){
        var cols = this.columns,  
            colCount = cols.length,
            i, c;                        
        this.colMenu.removeAll();                    
        for(i = 1; i < colCount; i++){
            c = cols[i];
            if(c.hideable !== false){
                this.colMenu.add(new Ext.menu.CheckItem({
                    itemId: 'col-' + i,
                    text: c.header,
                    checked: !c.hidden,
                    hideOnClick:false,
                    disabled: c.hideable === false
                }));
            }
        }
    },
                    
    // private
    handleHdMenuClick : function(item){
        var index = this.hdCtxIndex,
            id = item.getItemId();
        
        if(this.fireEvent('headermenuclick', this.columns[index], id, index) !== false) {
            index = id.substr(4);
            if(index > 0 && this.columns[index]) {
                this.setColumnVisible(index, !item.checked);
            }     
        }
        
        return true;
    },
    
    setColumnVisible : function(index, visible) {
        this.columns[index].hidden = !visible;        
        this.updateColumnWidths();
    },

    /**
     * Scrolls the grid to the top
     */
    scrollToTop : function(){
        this.innerBody.dom.scrollTop = 0;
        this.innerBody.dom.scrollLeft = 0;
    },

    // private
    syncScroll : function(){
        this.syncHeaderScroll();
        var mb = this.innerBody.dom;
        this.fireEvent('bodyscroll', mb.scrollLeft, mb.scrollTop);
    },

    // private
    syncHeaderScroll : function(){
        var mb = this.innerBody.dom;
        this.innerHd.dom.scrollLeft = mb.scrollLeft;
        this.innerHd.dom.scrollLeft = mb.scrollLeft; // second time for IE (1/2 time first fails, other browsers ignore)
    },
    
    registerNode : function(n) {
        Ext.ux.tree.TreeGrid.superclass.registerNode.call(this, n);
        if(!n.uiProvider && !n.isRoot && !n.ui.isTreeGridNodeUI) {
            n.ui = new Ext.ux.tree.TreeGridNodeUI(n);
        }
    }
    
    /**
     * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. 'id')
     * @param {String} attribute (optional) Defaults to null (return the actual nodes)
     * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
     * @return {Array}
     */
     ,
    getChecked : function(a, startNode){
        startNode = startNode || this.root;
        var r = [];
        function fn(node) {
            var arr = [];
            if(node.attributes.checked) {
                arr = [!a ? node : (a == 'id' ? node.id : node.attributes[a])];
            }
            if(node.childNodes) {
                Ext.each(node.childNodes,function(n) {
                    arr = arr.concat(fn(n));
                });
            }
            return arr;
        }
        var nodeArr = fn(startNode);
        return nodeArr;
    },
    setChecked:function(values,field) {
        (function (node) {
            var selfFn = arguments.callee;
            if(values.indexOf(node.attributes[field]) > -1) {
                node.ui.checkbox.defaultChecked = true;
                node.ui.checkbox.checked = true;
                node.attributes.checked = true;
            } else if(node.ui.checkbox){
                node.ui.checkbox.defaultChecked = false;
                node.ui.checkbox.checked = false;
                node.attributes.checked = false;
            }
            if(node.childNodes) {
                Ext.each(node.childNodes,function(n){
                    selfFn(n);
                });
            }
        })(this.root);
    }
});

Ext.reg('treegrid', Ext.ux.tree.TreeGrid);
    Ext.reg('tgbooleancolumn', Ext.tree.BooleanColumn);
})();

ZM.TriggerTreeGrid = Ext.extend(Ext.form.TriggerField, {    
    
    expanded: false,
    triggerClass:'x-form-pop-trigger',
    enableKeyEvents:true,
    
    initComponent:function() {
        ZM.TriggerTreeGrid.superclass.initComponent.call(this);
        var me = this;
        this.popup = new Ext.Layer(
        {
            constrain: false,
            shadow: true
        });
        
        this.treegrid = new Ext.ux.tree.TreeGrid({
            xtype:'treegrid',
            region:'center',
            useArrows:false,
            enableSort:false,
            preloadChildren:true,
            enableHdMenu:false,
            toggleChild:false, //是否触发子节点
            loader:new Ext.ux.tree.TreeGridLoader({
                url:this.url,
                dataRoot:'addon',
                preloadChildren:true,
                baseParams:this.params
            }),
            columns:this.columns
        });
                
        var elPanel = this.popup.createChild();
        new Ext.Panel({
            renderTo: elPanel,
            layout: "fit",
            bodyStyle:"padding:10px",
            width:500,
            height:300,
            labelWidth: 15,
            tbar:[
                    {xtype: "button", cls:'btn-show',text: Ext.langs.confirm, listeners: {"click": {fn: this.confirm, scope: this}}},
                    {xtype: "button", cls:'btn-show',text: Ext.langs.cancel, style:'margin-left:5px', listeners: {"click": {fn: this.cancel, scope: this}}}
                  ],
            items:this.treegrid
        });
        this.addEvents("confirm");
        this.addEvents("cancel");
    },
    onDestroy : function(){
        Ext.destroy(this.popup);
        ZM.TriggerTreeGrid.superclass.onDestroy.call(this);
    },
    onTriggerClick : function(e){
        ZM.TriggerTreeGrid.superclass.onTriggerClick.call(this,e);
        (this.expanded)?this.cancel():this.expand();
    },
    confirm: function()
    {
        var me = this;
        if(!this.isValid())
            return;
        var selRows = this.treegrid.getChecked();
        var arrVal = [];
        Ext.each(selRows,function(row,i){
            var v = row.attributes[me.field];
            if(Ext.isDefined(v))arrVal.push(v);
        });
        this.setValue(arrVal.join(','));
        this.collapse();
        this.focus();
        this.fireEvent('confirm', this);
    },
    expand: function()
    {
        var me = this;
        if(this.expanded || this.disabled)
            return;
        this.popup.alignTo(this.el, "tl-bl?");
        this.popup.show();
        this.expanded = true;
        me.treegrid.setChecked(me.getValue().split(','),me.field);
    },
    
    cancel:function()
    {
        this.collapse();
        //this.setValue(this.displayValue);
        this.focus();
        this.fireEvent('cancel', this);
    },

    collapse: function()
    {
        if(!this.expanded)
        {
            return;
        }
        this.popup.hide();
        this.expanded = false;
    },
    listeners:{
        keyup:function(field) {
            var me = field;
            me.treegrid.setChecked(me.getValue().split(','),me.field);
        }
    }
});
Ext.reg('triggertreegrid', ZM.TriggerTreeGrid);

Ext.override(Ext.tree.TreeNodeUI, {
    onClick : function(e){
       if(this.dropping){
            e.stopEvent();
            return;
        }
        if(this.fireEvent("beforeclick", this.node, e) !== false){
            var a = e.getTarget('a');
            if(!this.disabled && this.node.attributes.href && a){
                this.fireEvent("click", this.node, e);
                return;
            }else if(a && e.ctrlKey){
                e.stopEvent();
            }
            //change treenode a tag can link
            //edit by klj 2013-07-08
            if(a &&　a.className.indexOf('x-tree-node-anchor') >= 0) {
                e.preventDefault();
            }
            if(this.disabled){
                return;
            }

            if(this.node.attributes.singleClickExpand && !this.animating && this.node.isExpandable()){
                this.node.toggle();
            }

            this.fireEvent("click", this.node, e);
        }else{
            e.stopEvent();
        }
    }
});